package com.strutor.tree;


import com.strutor.queue.LinkedQueue;

import java.util.Queue;
import java.util.Stack;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 要实现二分搜索树，就必须保证存储的数据可比较，需要继承 @link Comparable
 */
public class BinarySearchTree<E extends Comparable<E>> {
    private class Node {
        public E e;
        public Node left;
        public Node right;

        public Node(E e, Node left, Node right) {
            this.e = e;
            this.left = left;
            this.right = right;
        }

        public Node(E e) {
            this(e, null, null);
        }

        @Override
        public String toString() {
            return e.toString();
        }
    }


    private Node root;
    private int size;

    public BinarySearchTree() {
        root = null;
        size = 0;
    }

    public int getSize() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }


    public void add(E e) {
        if (root == null) {
            root = new Node(e);
            size++;
        } else {
            add(root, e);
        }
    }

    private void add(Node node, E e) {
        if (e.equals(node.e)) {
            return;
        } else if (node.left == null && e.compareTo(node.e) < 0) {
            node.left = new Node(e);
            size++;
            return;
        } else if (node.right == null && e.compareTo(node.e) > 0) {
            node.right = new Node(e);
            size++;
            return;
        }

        if (e.compareTo(node.e) < 0) {
            add(node.left, e);
        } else {
            add(node.right, e);
        }
    }

    public void add2(E e) {
        root = add2(root, e);
    }

    private Node add2(Node node, E e) {
        if (node == null) {
            size++;
            return new Node(e);
        }
        if (e.compareTo(node.e) < 0) {
            node.left = add2(node.left, e);
        } else if (e.compareTo(node.e) > 0) {
            node.right = add2(node.right, e);
        }
        return node;
    }

    public boolean contains(E e) {
        return contains(root, e);
    }

    private boolean contains(Node node, E e) {
        if (node == null) {
            return false;
        }
        if (e.compareTo(node.e) == 0) {
            return true;
        } else if (e.compareTo(node.e) < 0) {
            return contains(node.left, e);
        } else {
            return contains(node.right, e);
        }
    }

    //前序遍历
    private void preOrder() {
        preOrder(root);
    }

    private void preOrder(Node node) {
        if (node == null) {
            return;
        }
        System.out.println(node.e);
        preOrder(node.left);
        preOrder(node.right);
    }

    //非递归遍历
    public void preOrderNR() {
        Stack<Node> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            Node cur = stack.pop();
            System.out.println(cur.e);

            if (cur.right != null) {
                stack.push(cur.right);
            }
            if (cur.left != null) {
                stack.push(cur.left);
            }
        }
    }


    private void generateBSTString(Node node, int deepth, StringBuilder res) {
        if (node == null) {
            res.append(generatorDeepthStr(deepth) + "null\n");
            return;
        }
        res.append(generatorDeepthStr(deepth) + node.e + "\n");
        generateBSTString(node.left, deepth + 1, res);
        generateBSTString(node.right, deepth + 1, res);
    }

    private String generatorDeepthStr(int deepth) {
        StringBuilder res = new StringBuilder();
        for (int i = 0; i < deepth; i++) {
            res.append("--");
        }
        return res.toString();
    }


    @Override
    public String toString() {
        //前序遍历 这三种都属于深度优先遍历
        StringBuilder res = new StringBuilder("BST Tree");
        generateBSTString(root, 0, res);

//        preOrderNR();
        System.out.println("----------------------------------");
        //中序遍历
//        StringBuilder res = new StringBuilder("BST Tree");
//        inOrder(root,res);

        //后续遍历
//        StringBuilder res = new StringBuilder("BST Tree");
//        postOrder(root,res);

        //广度优先遍历
        levelOrder();
        return res.toString();
    }

    //广度优先遍历
    public void levelOrder() {
        Queue<Node> queue = new LinkedBlockingQueue<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            Node cur = queue.remove();
            System.out.println(cur.e);

            if (cur.left != null) {
                queue.add(cur.left);
            }
            if (cur.right != null) {
                queue.add(cur.right);
            }
        }

    }

    //中序遍历
    private void inOrder(Node node, StringBuilder res) {
        if (node == null) {
            res.append(" null\n");
            return;
        }

        inOrder(node.left, res);
        res.append(node.e);
        inOrder(node.right, res);
    }

    //后序遍历
    private void postOrder(Node node, StringBuilder res) {
        if (node == null) {
            res.append(" null\n");
            return;
        }
        postOrder(node.left, res);
        postOrder(node.right, res);
        res.append(node.e + " ");
    }


    public E getMinNR() {
        if (size == 0) {
            throw new IllegalArgumentException("Tree is Empty");
        }
        Node cur = root;
        while (cur.left != null) {
            cur = cur.left;
        }
        return cur.e;
    }

    public E getMaxNR() {
        if (size == 0) {
            throw new IllegalArgumentException("Tree is Empty");
        }
        Node cur = root;
        while (cur.right != null) {
            cur = cur.right;
        }
        return cur.e;
    }
    public E getMin(){
        if(size ==0){
            throw new IllegalArgumentException("Tree is Empty");
        }

        return getMinNode(root).e;
    }

    private Node getMinNode(Node node) {
        if (node.left == null){
            return node;
        }
        return getMinNode(node.left);
    }

    public E getMax(){
        if (size ==0){
            throw new IllegalArgumentException("Tree is Empty");
        }
        return getMaxNode(root).e;
    }

    private Node getMaxNode(Node node) {
        if (node.right == null){
            return node;
        }
        return getMaxNode(node.right);
    }

    public E removeMin(){
        E ret = getMin();
        root = removeMin(root);
        return ret;
    }

    private Node removeMin(Node node){
        if (node.left == null){
            Node rightNode = node.right;
            node.right = null;
            size --;
            return rightNode;
        }
        node.left =  removeMin(node.left);
        return node;
    }

    public E removeMax(){
        E ret = getMax();
        root = removeMax(root);
        return ret;
    }

    private Node removeMax(Node node){
        if (node.right == null){
            Node leftNode = node.left;
            node.left = null;
            size --;
            return leftNode;
        }
        node.right = removeMax(node.right);
        return node;
    }

    public void remove(E e){
        root = postRemove(root,e);
    }

    //后继remove hibbard 思想
    private Node postRemove(Node node, E e){
        if (node == null){
            return null;
        }
        if (e.compareTo(node.e) <0){
            postRemove(node.left,e);
            return node;
        }else if (e.compareTo(node.e) >0){
            postRemove(node.right,e);
            return node;
        }else{
            if (node.left == null){
                Node rightNode = node.right;
                node.right = null;
                size--;
                return rightNode;
            }
            if (node.right == null){
                Node leftNode = node.left;
                node.left = null;
                size--;
                return leftNode;
            }
            Node successor = getMinNode(node.right);
            successor.left=node.left;
            successor.right=removeMin(node.right);
            node.left=node.right=null;
            return successor;
        }
    }

    //前驱 remove hibbard 思想
    private Node prevRemove(Node node ,E e){
        if (node == null){
            return null;
        }
        if (e.compareTo(node.e) <0){
            prevRemove(node.left,e);
            return node;
        }else if (e.compareTo(node.e)>0){
            prevRemove(node.right,e);
            return node;
        }else{
            if (node.right == null){
                Node leftNode = node.left;
                node.left = null;
                size --;
                return leftNode;
            }
            if (node.left == null){
                Node rightNode = node.right;
                node.right = null;
                size--;
                return rightNode;
            }
            Node predecessor = getMaxNode(node.left);
            predecessor.left=removeMax(node.left);
            predecessor.right = node.right;
            node.left=node.right=null;
            return predecessor;
        }
    }

    public static void main(String[] args) {
        BinarySearchTree<Integer> bst = new BinarySearchTree<>();
        int[] num = {8, 45, 36, 5, 10, 256, 2, 21, 82, 20};
        for (int i = 0; i < 10; i++) {
            bst.add2(num[i]);
        }
        System.out.println(bst.getMin());
        bst.removeMin();
        System.out.println(bst.getMin());
        System.out.println("------------------------------");
        System.out.println(bst.getMax());
        bst.removeMax();
        System.out.println(bst.getMax());
    }
}
